package com.dz.lm.web.filter;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.*;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dz.lm.common.util.FileUpOrDownUtil;
import com.google.gson.JsonObject;
import com.smartlbs.util.Base64Img;
import com.smartlbs.util.Mapper;
import com.smartlbs.util.StringUtil;
import com.smartlbs.util.UploadFile;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.dz.lm.common.exception.DaoException;
import com.dz.lm.common.utils.json.JsonUtils;
import com.dz.lm.common.utils.security.RSAUtil;
import com.dz.lm.dao.appLogin.read.AppLoginDao;
import com.dz.lm.dao.log.read.LoginLogDao;

public class CheckLoginFilter implements Filter {
	
	private static String RSAPRIVATEKEY = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAKsLb3vSnld5insTo2C6x3f6JS0S30Pzhrx6xk2b99A/t+12mvl0utwxVzXxiO0n2Aamlvl7OUaXnj3s8NYdExwdYTsF46nz4mZgk+nctg7iTbIT7WUPHELMVVFDvcD9nzVPASzJv0FNAO78UmGGv+cprQ07nQP1LxU7ki1w9IRLAgMBAAECgYEAo5yXsmjgn6oaJeq+EAv6O7CimQABYv1yd541TA2SObiJlnMqgM4A5BmqY2Y8ZSYExS/bIJ+XRQhJDNE1+onrORjmvYUuUjxeRJq8AmIc5wdmBUrJ8+lSNfDhumIA4BCgDMci8xV8GacBqDd6Nh/TihXtPau/Xp5JP+hneXGOuSECQQDtuB0G+yKlOXLRyjkyzZRVw7aT8HAaDGHNF1pmgaZH4GbdCsDFEuVaIEpVkqC8YbLFRviNIsgxx5FLKG+icARbAkEAuDK58D2QliquUceZSdOp7BRzvmwLr42/ihAi8biuDutoCvMTl9sAiBz/pZVcwdnSO0d1iaJ1wr5L1+nmNtzC0QJBAMSboM5USKw0XmVqhnIhG0zvqIKkumKg2QaiCO98zUTnMMwih5q27R/kUvaBZhVIDG4jK5C3MrIRJ3bsw5+qW78CQHqBaj7Ig1gMTOGhEWcTeijENXKJI4B/kss9DjCbtk+/6vOVVQujIQhl2PUEkKtwtiysyxRd01pQ+9o++ti0HHECQQDBDLuz/7b6DT2f8ueYqgfr+FGB32rXyVSYrT8MeLHd7M7wFlzZkhNAkgOz6AQiE+kPecjiM9QsphxXhcI2tWQa";

	public Logger logger = LogManager.getLogger(getClass());
	
	private List<String> trustURLList = new ArrayList<String>();
	private List<String>  h5Url = new ArrayList<String>();
	
    private LoginLogDao loginLogDao;
    private AppLoginDao rAppLoginDao;

	/**
	 * 初始化参数
	 */
	public void init(FilterConfig filterConfig) throws ServletException {		
		ApplicationContext ac = new FileSystemXmlApplicationContext("classpath:URLFilterConfig.xml");
		URLFilter sslconfig =  (URLFilter)ac.getBean("urlFilter");
		if(sslconfig != null){
			trustURLList  = sslconfig.getTrustList();
			h5Url = sslconfig.getH5Url();
		}
		WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(filterConfig.getServletContext());
		loginLogDao = (LoginLogDao) wac.getBean(LoginLogDao.class);
		rAppLoginDao = (AppLoginDao) wac.getBean(AppLoginDao.class);
	}
	
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
			FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;
		HttpSession session = request.getSession();
		session.setAttribute("ssid", session.getId());
		String uri = request.getServletPath()+ (request.getPathInfo() == null ? "" : request.getPathInfo());
		request.setAttribute("imgUrl", request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort());
		String urlArray[] = uri.split("/");
		logger.info(urlArray[urlArray.length - 1] + " start");
		if (uri.indexOf(".png") > 0 || uri.indexOf(".jpg") > 0 || uri.indexOf(".css") > 0 || uri.indexOf(".html") > 0 || uri.indexOf(".js") > 0 || uri.indexOf(".jsp") > 0 || uri.indexOf("error.do") > 0) {
			//TODO
		} else if (uri.indexOf("wxPayCallBack.do") > 0) {
			String orderId = uri.substring(uri.indexOf("pay/") + 4,uri.indexOf("/wxPayCallBack.do"));
			request.setAttribute("orderId", orderId);
			if (orderId == null || "".equals(orderId)) {
				logger.error("wxPayCallBack：URL异常！");
				return;
			}
		} else if (checkH5URI(request,uri)) {
			boolean paramFlag = checkContentType2(request);
	    	if (paramFlag) {
	        	logger.error("09","参数为空或参数异常!");
	        	response.sendRedirect(request.getContextPath() + "/app/error.do?type=1&reqKey=" + request.getAttribute("reqKey"));
	        	return;
	    	}
	    	//公司
		} else if(checkCOMPURI(request,uri)){
			boolean paramFlag = checkContentCompType(request,response,uri);
			if (paramFlag) {
				logger.error("09","参数为空或参数异常!");
				response.sendRedirect(request.getContextPath() + "/app/error.do?type=1&reqKey=" + request.getAttribute("reqKey"));
				return;
			}
		}else {
			// 解密
			boolean paramFlag = checkContentType(request,response,uri);
			Boolean validPass = (Boolean) request.getAttribute("accessTokenValidPass");
			validPass = validPass == null ? false : validPass;
	    	if (paramFlag) {
	        	logger.error("09","参数为空或参数异常!");
	        	response.sendRedirect(request.getContextPath() + "/app/error.do?type=1&reqKey=" + request.getAttribute("reqKey"));
	        	return;
	    	} else if (!validPass.booleanValue() && !checkTrustURI(request,uri)) {
	        	logger.error("10","登录已失效请重新登录!");
	        	response.sendRedirect(request.getContextPath() + "/app/error.do?type=2&reqKey=" + request.getAttribute("reqKey"));
	        	return;
	    	}
		}
		try {
			filterChain.doFilter(request, response);
		} catch(Exception e){
			e.printStackTrace();
			response.sendRedirect(request.getContextPath() + "/app/error.do?type=3&reqKey=" + request.getAttribute("reqKey"));
		}
		logger.info(urlArray[urlArray.length - 1] + " end");
	}

	/**
	 * 请求内容类型区分（form-data/json）
	 * 
	 **/
	public boolean checkContentType(HttpServletRequest request,HttpServletResponse response,String url) {
//		String _reqKey = "oQLf9X+AJ6/7fDXtIfEMtNNXohnNIv3j/cSlYWH34E5afjDl9BeFDXEY3MZq6kYfFdR8E9pB/U6WtHpKlA+C0kNIt+PUgCKJ23xNPjBNvauZF4Zb9pdXUei9DLQDkL4KYMX4kYwMzPoCM7rVpV+oTS9eyjZrmKmq5F+aNxSAl1M=";
//    	String _reqData = "crUt1Mj0PeFlj4cJVPhTL2svlx7E/1VEq2GSzAthVjd1B5lKKBGWcFxI6XYak+vnP9TTBl8IEVQ=";
		boolean paramFlag = false;
		Map<String, Object> param = new HashMap<>();
		Map<String, Object> images = new HashMap<>();
		if (request.getContentType()!= null && request.getContentType().toString().indexOf("multipart/form-data") >= 0) {
			try {
		       //创建工厂
		        DiskFileItemFactory factory = new DiskFileItemFactory();
		        // 设置缓冲区大小，这里是400kb
		        factory.setSizeThreshold(10240 * 100);
		        // 设置缓冲区目录
		        ServletFileUpload upload = new ServletFileUpload(factory);
		        upload.setHeaderEncoding("utf-8");
		        //设置上传文件的大小 12M
		        upload.setSizeMax(4194304 * 3);
		        //创建解析器 // 得到所有的文件
		        List<FileItem> items = upload.parseRequest(request);
		        Iterator<FileItem> i = items.iterator();
		        while (i.hasNext()) {
		            FileItem fi = i.next();
		            // false表示文件 否则字段
		            if (!fi.isFormField()) {
		                String fileName = fi.getName();
		                if (fileName != null) {
	                    	images.put(fi.getFieldName(), fi);
	                    } else {
	                    	logger.info("未找到文件或已丢失");
	                    }
		            } else {
						fi.getString("UTF-8");
						param.put(new String(fi.getFieldName().getBytes("iso-8859-1"), "utf-8"),
								new String(fi.getString().getBytes("iso-8859-1"), "utf-8"));        
		            }
		        }
				/*FileUpOrDownUtil fileUpOrDown = new FileUpOrDownUtil();
				Map<String, Object> fileObj = fileUpOrDown.fileUp(request, response);
				Map formFieldMap = (Map)fileObj.get("formField");
				List<UploadFile> fList = (List<UploadFile>)fileObj.get("fileField");
				param.putAll(formFieldMap);*/
		        if (param.get("reqData") != null && param.get("reqKey") != null) {
                	request.setAttribute("images",images);
                	parameterDecrypt(request, response,param, paramFlag,url);
		        } else {
					logger.info("请求参数为空");
					paramFlag = true;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			StringBuffer info = new StringBuffer();
			InputStream in;
			try {
				in = request.getInputStream();
				BufferedInputStream buf = new BufferedInputStream(in);
				byte[] buffer = new byte[1024];
				int iRead;
				while ((iRead = buf.read(buffer)) != -1) {
					info.append(new String(buffer, 0, iRead, "UTF-8"));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

			if(info != null && info.length() > 0) {
				param = JsonUtils.readValue(info.toString());
				parameterDecrypt(request, response,param, paramFlag,url);
			} else {
				logger.info("请求参数为空");
				paramFlag = true;
			}
		}
		return paramFlag;
	}
	
	/**
	 * 请求内容类型区分（form-data/json）
	 * 
	 **/
	public boolean checkContentType2(HttpServletRequest request) {
		boolean paramFlag = false;
		Map<String, Object> param = new HashMap<>();
		Map<String, Object> images = new HashMap<>();
		if (request.getContentType()!= null && request.getContentType().toString().indexOf("multipart/form-data") >= 0) {
			try {
		        //创建工厂
		        DiskFileItemFactory factory = new DiskFileItemFactory();
		        // 设置缓冲区大小，这里是400kb
		        factory.setSizeThreshold(10240 * 100);
		        // 设置缓冲区目录
		        ServletFileUpload upload = new ServletFileUpload(factory);
		        upload.setHeaderEncoding("utf-8");
		        //设置上传文件的大小 12M
		        upload.setSizeMax(4194304 * 3);
		        //创建解析器 // 得到所有的文件
		        List<FileItem> items = upload.parseRequest(request);
		        Iterator<FileItem> i = items.iterator();
		        while (i.hasNext()) {
		            FileItem fi = i.next();
		            // false表示文件 否则字段
		            if (!fi.isFormField()) {
		                String fileName = fi.getName();
		                if (fileName != null) {
	                    	images.put(fi.getFieldName(), fi);
	                    } else {
	                    	logger.info("未找到文件或已丢失");
	                    }
		            } else {
						fi.getString("UTF-8");
						param.put(new String(fi.getFieldName().getBytes("iso-8859-1"), "utf-8"),
								new String(fi.getString().getBytes("iso-8859-1"), "utf-8"));  
		            }
		        }
		        request.setAttribute("images",images);
		        if (!param.isEmpty()) {
    				request.setAttribute("reqData", param);
    				logger.info("请求参数：" + param.toString());
		        } else {
					logger.info("请求参数为空");
					paramFlag = true;
				}
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (FileUploadException e) {
				e.printStackTrace();
			}
		} else {
			StringBuffer info = new StringBuffer();
			InputStream in;
			try {
				in = request.getInputStream();
				BufferedInputStream buf = new BufferedInputStream(in);
				byte[] buffer = new byte[1024];
				int iRead;
				while ((iRead = buf.read(buffer)) != -1) {
					info.append(new String(buffer, 0, iRead, "UTF-8"));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

			if(info != null && info.length() > 0) {
				param = JsonUtils.readValue(info.toString());
				logger.info("请求参数：" + info.toString());
				if (param.get("reqData") != null && !"null".equals(param.get("reqData")) && !"".equals(param.get("reqData"))) {
    				request.setAttribute("_reqData", param.get("reqData"));
    				request.setAttribute("reqData", param.get("reqData"));
    				//Token
    	    		@SuppressWarnings("unchecked")
					Object accessToken = ((Map<String, Object>) param.get("reqData")).get("accessToken");
    	    		if (accessToken != null && !"".equals(accessToken)) {
    	        		try {
    	        			Map<String, Object> user = loginLogDao.checkAccessToken(accessToken);
    	        			if (user != null && user.get("userId") != null) {
    	        				request.setAttribute("accessTokenValidPass", true);
    	        				request.setAttribute("userId", user.get("userId"));
    	        			}
    	    			} catch (DaoException e) {
    	    				e.printStackTrace();
    	    			}
    	    		}
		        } else {
					logger.info("请求参数为空");
					paramFlag = true;
				}
			} else {
				logger.info("请求参数为空");
				paramFlag = true;
			}
		}
		return paramFlag;
	}
	/**公司
	 * 请求内容类型区分（form-data/json）
	 *
	 **/
	public boolean checkContentCompType(HttpServletRequest request,HttpServletResponse response,String url) {
		boolean paramFlag = false;
		Map<String, Object> param = new HashMap<>();
		Map<String, Object> images = new HashMap<>();
		if (request.getContentType()!= null && request.getContentType().toString().indexOf("multipart/form-data") >= 0) {
			try {
				//创建工厂
				DiskFileItemFactory factory = new DiskFileItemFactory();
				// 设置缓冲区大小，这里是400kb
				factory.setSizeThreshold(10240 * 100);
				// 设置缓冲区目录
				ServletFileUpload upload = new ServletFileUpload(factory);
				upload.setHeaderEncoding("utf-8");
				//设置上传文件的大小 12M
				upload.setSizeMax(4194304 * 3);
				//创建解析器 // 得到所有的文件
				List<FileItem> items = upload.parseRequest(request);
				Iterator<FileItem> i = items.iterator();
				while (i.hasNext()) {
					FileItem fi = i.next();
					// false表示文件 否则字段
					if (!fi.isFormField()) {
						String fileName = fi.getName();
						if (fileName != null) {
							images.put(fi.getFieldName(), fi);
						} else {
							logger.info("未找到文件或已丢失");
						}
					} else {
						fi.getString("UTF-8");
						param.put(new String(fi.getFieldName().getBytes("iso-8859-1"), "utf-8"),
								new String(fi.getString().getBytes("iso-8859-1"), "utf-8"));
					}
				}
				/*FileUpOrDownUtil fileUpOrDown = new FileUpOrDownUtil();
				Map<String, Object> fileObj = fileUpOrDown.fileUp(request, response);
				Map formFieldMap = (Map)fileObj.get("formField");
				List<UploadFile> fList = (List<UploadFile>)fileObj.get("fileField");
				param.putAll(formFieldMap);*/
				if (param.get("reqData") != null && param.get("reqKey") != null) {
					request.setAttribute("images",images);
					parameterDecrypt(request, response,param, paramFlag,url);
				} else {
					logger.info("请求参数为空");
					paramFlag = true;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			StringBuffer info = new StringBuffer();
			InputStream in;
			try {
				in = request.getInputStream();
				BufferedInputStream buf = new BufferedInputStream(in);
				byte[] buffer = new byte[10240];
				int iRead;
				while ((iRead = buf.read(buffer)) != -1) {
					info.append(new String(buffer, 0, iRead, "UTF-8"));
				}
			} catch (IOException e) {
				e.printStackTrace();
			}

			if(info != null && info.length() > 0) {
				param = JsonUtils.readValue(info.toString());
				Map reqData = (Map)param.get("reqData");
				Set<String> keys = reqData.keySet();
				List list=new LinkedList();
				List<String> removes = new ArrayList<>();
				for (String key : keys) {
					String value = reqData.get(key).toString();
					if(!StringUtil.containEmpty(value)){
						if(value.startsWith("data:image") && value.indexOf(";base64,") > -1){
							String[] typeAndValue = value.split(";base64,");
							String base64 = typeAndValue[1];
							String suffix = typeAndValue[0].split("/")[1];
							UploadFile fileVo = new UploadFile();
							String name = Base64Img.getUUid()+"."+suffix;
							//byte[] bytes = Base64Img.getBytes(base64);
							byte[] bytes = Base64.decodeBase64(base64);
							fileVo.setFile_bytes(bytes);
							fileVo.setFile_name(name);
							fileVo.setFile_size(bytes.length);
							fileVo.setField_name(key);
							list.add(fileVo);
							removes.add(key);
						}
					}
				}
				for (String remove : removes) {
					reqData.remove(remove);
				}
				param.put("reqData",reqData);
				request.setAttribute("fileField", list);
				parameterDecrypt(request, response,param, paramFlag,url);
			} else {
				logger.info("请求参数为空");
				paramFlag = true;
			}
		}
		return paramFlag;
	}
	/**
	 * 解密及校验Token
	 * @param request
	 * @param param
	 * @param paramFlag
	 * @return void
	 */
	private void parameterDecrypt(HttpServletRequest request, HttpServletResponse response, Map<String, Object> param, boolean paramFlag, String url){
		String _reqData = JSON.toJSONString(param.get("reqData"));
		request.setAttribute("_reqData", _reqData);
		request.setAttribute("_reqKey",param.get("reqKey"));
		String _reqKey =  param.get("reqKey") == null ? "" : JSON.toJSONString(param.get("reqKey"));
    	if (_reqData != null && !"".equals(_reqData) && _reqKey != null && !"".equals(_reqKey)) {
        	String key = new String(RSAUtil.decryptByRSA(RSAPRIVATEKEY, _reqKey));
        	String reqData = RSAUtil.decryptBy3Des(key, _reqData);
			JSONObject jsonObject = JSONObject.parseObject(reqData);
    		Map<String, Object> dataMap = JsonUtils.readValue(reqData);
    		//Token
    		Object accessToken = dataMap.get("accessToken");
    		if (accessToken != null && !"".equals(accessToken)) {
        		try {
        			Map<String, Object> user = loginLogDao.checkAccessToken(accessToken);
        			//
        			if ((user != null && user.get("userId") != null ) ) {
        				request.setAttribute("accessTokenValidPass", true);
        				request.setAttribute("userId", user.get("userId"));

        			}else if ( dataMap.get("platform").equals("Android") ){
						request.setAttribute("accessTokenValidPass", false);
					}

    			} catch (DaoException e) {
    				e.printStackTrace();
    			}
    		}else {
				request.setAttribute("accessTokenValidPass", false);
			}

			String s = jsonObject.toJSONString();
			request.setAttribute("reqData",reqData);
			request.setAttribute("_reqData", s);
			request.setAttribute("reqKey",key);
        	logger.info("解密后参数：reqData=" + reqData);
    	} else {
			Map<String, Object> params = JsonUtils.readValue(_reqData);
			Object accessToken = params.get("accessToken");
			if (accessToken != null && !"".equals(accessToken)) {
				try {
					Map<String, Object> user = loginLogDao.checkAccessToken(accessToken);
					//
					if ((user != null && user.get("userId") != null ) ) {
						request.setAttribute("accessTokenValidPass", true);
						request.setAttribute("userId", user.get("userId"));
					}else {
						request.setAttribute("accessTokenValidPass", false);
					}
					if (params.get("userId") != null & !"".equals(params.get("userId")) && params.get("userId").toString().length() == 32) {
						Map<String, Object> userInfo = rAppLoginDao.qryUserIdByMd5UserId(params);
						params.put("userId", userInfo.get("userId"));
					}
				} catch (DaoException e) {
					e.printStackTrace();
				}
			}else {
				request.setAttribute("accessTokenValidPass", false);
			}
			request.setAttribute("reqData",null);
        	request.setAttribute("reqKey",null);
    	}
	}

	/**
	 * 当前访问页面是否在检查的URL列表中
	 */
	private boolean checkTrustURI(HttpServletRequest request, String uri) {
		if("/".equals(uri)){
			return true;
		}
		for (String _url : trustURLList) {
			if (uri.matches(_url)) {
				return true;
			}
		}
		if(uri.contains("comp")){
			return true;
		}
		return false;
	}

	/**
	 * 当前接口是否在H5页面请求URL列表中
	 */
	private boolean checkH5URI(HttpServletRequest request, String uri) {
		String uriTemp = uri != null && uri.indexOf("/dz-lm-web") >= 0 ? uri.substring(10, uri.length()) : uri; 
		for (String _url : h5Url) {
			if (uriTemp.matches(_url)) {
				return true;
			}
		}
		return false;
	}
	/**
	 * 当前接口是否在H5页面请求URL列表中
	 */
	private boolean checkCOMPURI(HttpServletRequest request, String uri) {
		if(uri.contains("comp")){
			return true;
		}else {
			return false;
		}
	}


	public void destroy() {
		trustURLList.clear();
		h5Url.clear();
	}
}
